/*
 *多文件合并
 */
package filemerge

import (
	"fmt"
	"io/ioutil"
	"lark/src/lexer"
	"log"
	"os"
	"path/filepath"
	"strings"
)

type FileMerge struct {
	SourceCode     map[string]string
	ImportList     []string
	TempImportList []string //临时存储import的列表,倒序后在清空
}

/*
- 文件合并获取代码
- 多文件合并,生成一个文件（sourceCode.lac）
*/
func GetSourceCode(fileName string) string {
	currentDir, err := os.Getwd() // 获取当前工作目录
	if err != nil {
		fmt.Println("Error getting current directory:", err)
	}
	runFilePath := currentDir + "\\main.la"
	if fileName != "" {
		runFilePath = fileName
	}
	//获取主文件源码
	mainInputCode, err := ioutil.ReadFile(runFilePath)
	if err != nil {
		log.Fatal(err)
	}

	// fileStart := "//====== start " + fileName + " =======\n"
	// fileContent := string(mainInputCode) + "\n"
	// fileEnd := "//====== end " + fileName + " =======\n"
	// mainInputCode = fileStart + fileContent + fileEnd

	sourceCode := ""
	// var fm FileMerge
	fm := &FileMerge{
		SourceCode: make(map[string]string),
	}

	//获取源码
	fm.readFilesInCurrentDirSubdirectories(currentDir)
	// fm.SourceCode["main.la"] = string(mainInputCode)

	// 递归按顺序获取源码生成数组
	fm.retrieveSourceCodeAndGenerateArray(string(mainInputCode), 0)
	// 数组源码生成字符串
	code := fm.convertArrayToString()
	sourceCode += code
	sourceCode += string(mainInputCode)

	// 输出间隔符
	// utils.PrintSeparator()

	sourceCodeFileName := currentDir + "/sourceCode.lac"
	// 检查文件是否存在
	_, err = os.Stat(sourceCodeFileName)
	if os.IsNotExist(err) {
		//不存在
		//多文件合并成一个文件
		err = ioutil.WriteFile(sourceCodeFileName, []byte(sourceCode), 0644)
		if err != nil {
			fmt.Println("创建文件失败：", err)
		}
	} else {
		//存在
		err = os.Remove(sourceCodeFileName)
		if err != nil {
			fmt.Println("删除文件失败：", err)
		} else {
			// fmt.Println("文件已成功删除")
		}
		//多文件合并成一个文件
		err = ioutil.WriteFile(sourceCodeFileName, []byte(sourceCode), 0644)
		if err != nil {
			fmt.Println("创建文件失败：", err)
		}
	}
	// fmt.Println(fm.SourceCode)
	return sourceCode
}

// 数组源码生成字符串
func (fm *FileMerge) convertArrayToString() string {
	var codeStr string
	for _, v := range fm.ImportList { // 遍历文件列表
		codeStr += v + "\n\n"
	}
	return codeStr
}

/**
 * 递归按顺序获取源码生成数组
 * 递归调用
 * depth :深度
 */
func (fm *FileMerge) retrieveSourceCodeAndGenerateArray(code string, depth int) {
	lex := lexer.New(code)
	for tok := lex.NextToken(); tok.Type != lexer.EOF; tok = lex.NextToken() {
		// fmt.Printf("%+v\n", tok)
		if tok.Literal == "import" {
			tok = lex.NextToken() // 获取import后的第一个token
			var sourceCode string
			//判断包中否有/
			if strings.Contains(tok.Literal, "/") {
				// fmt.Println("字符串包含子字符串")
				//转数组获取最后一个元素
				packageNameArr := strings.Split(tok.Literal, "/")
				packageName := packageNameArr[len(packageNameArr)-1]
				sourceCode = fm.SourceCode[packageName]
			} else {
				// fmt.Println("字符串不包含子字符串")
				sourceCode = fm.SourceCode[tok.Literal]
			}

			fm.TempImportList = append(fm.TempImportList, sourceCode)
			fm.retrieveSourceCodeAndGenerateArray(sourceCode, depth+1) // 递归调用

			if depth == 0 {
				fm.ImportList = append(fm.ImportList, reverseSlice(fm.TempImportList)...)
				// 清空数组
				fm.TempImportList = []string{}
			}

		}
	}
}

// 接受任何类型的切片并倒序
func reverseSlice(strArray []string) []string {
	for i, j := 0, len(strArray)-1; i < j; i, j = i+1, j-1 {
		strArray[i], strArray[j] = strArray[j], strArray[i]
	}
	return strArray
}

/*
 * 读取当前目录下的所文件和子目录中的文件
 * dir :当前目录
 */
func (fm *FileMerge) readFilesInCurrentDirSubdirectories(dir string) {

	files, err := os.ReadDir(dir) // 读取当前目录下的所有文件和文件夹
	if err != nil {
		fmt.Println("Error reading directory:", err)
	}
	// 遍历文件和文件夹
	for _, file := range files {
		// fmt.Println(file.Name()) // 打印每个文件或文件夹的名称
		if file.IsDir() {
			fullPath := filepath.Join(dir, file.Name())

			fm.readFilesInCurrentDirSubdirectories(fullPath)

		} else {
			//跳过main.la文件
			if file.Name() == "main.la" {
				continue
			}
			//判断文件后缀名是否为 .la
			ext := filepath.Ext(file.Name())
			if ext == ".la" {
				fullPath := filepath.Join(dir, file.Name())

				/* content += "PACKAGE_START "
				content += file.Name()
				content += "\n"
				content += readFileContent(fullPath)
				content += "\n"
				content += "PACKAGE_END"
				content += "\n\n" */

				// 使用TrimSuffix去掉文件后缀
				fileName := strings.TrimSuffix(file.Name(), ".la")
				fileStart := "//====== start " + fileName + " =======\n"
				fileContent := fm.readFile(fullPath) + "\n"
				fileEnd := "//====== end " + fileName + " =======\n"
				fm.SourceCode[fileName] = fileStart + fileContent + fileEnd

			}
		}
	}
	// contentMap := fmt.Sprintf("%v", contentMap)
}

// 读取文件内容
func (fm *FileMerge) readFile(filePath string) string {
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		fmt.Println("Error reading file:", err)
	}
	// fmt.Println(string(data)) // 打印文件内容
	return string(data)
}
